﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace NewlifeCC
{
    class Character : INotifyPropertyChanged, IDataErrorInfo
    {
        private TextInfo ti = new CultureInfo("en-US", false).TextInfo;
        public Type type { get; } = Type.MALE;
        public bool enabled { get; set; } = true;
        private int _priority = 0;
        public int priority { get { return _priority; } set { _priority = value; NotifyPropertyChanged(); } }
        private string _name = "Bob";

        public event PropertyChangedEventHandler PropertyChanged;

        public string name
        {
            get
            {
                return _name;
            }
            set
            {

                _name = ti.ToTitleCase(value);
                NotifyPropertyChanged();
            }
        }
        public Age age { get; set; } = Age.THIRTIES;
        public IEnumerable<Age> ageValues
        {
            get { return Enum.GetValues(typeof(Age)).Cast<Age>(); }
        }
        private String _race = "black";
        public String race
        {
            get
            {
                return _race;
            }
            set
            {
                _race = value;
                NotifyPropertyChanged();
                PropertyChanged(this, new PropertyChangedEventArgs("eyeColour"));
                PropertyChanged(this, new PropertyChangedEventArgs("hairColour"));
                PropertyChanged(this, new PropertyChangedEventArgs("skinColour"));
                PropertyChanged(this, new PropertyChangedEventArgs("Error"));
            }
        }
        private String _eyeColor = "";
        public String eyeColour { get { return _eyeColor; } set { _eyeColor = value;
                NotifyPropertyChanged();
                PropertyChanged(this, new PropertyChangedEventArgs("Error"));
            } }
        private String _hairColour = "";
        public String hairColour
        {
            get { return _hairColour; }
            set
            {
                _hairColour = value;
                NotifyPropertyChanged();
                PropertyChanged(this, new PropertyChangedEventArgs("Error"));
            }
        }
        private string _skinColour = "";
        public String skinColour
        {
            get { return _skinColour; }
            set
            {
                _skinColour = value;
                NotifyPropertyChanged();
                PropertyChanged(this, new PropertyChangedEventArgs("Error"));
            }
        }
        public Figure figure { get; set; } = Figure.TONED;
        public IEnumerable<Figure> figureValues
        {
            get { return Enum.GetValues(typeof(Figure)).Cast<Figure>(); }
        }
        public Personality personality { get; set; } = Personality.AVERAGE;
        public IEnumerable<Personality> personalityValues
        {
            get { return Enum.GetValues(typeof(Personality)).Cast<Personality>(); }
        }
        public ObservableCollection<Trait> traits { get; set; } = new ObservableCollection<Trait>() { Trait.HATES_CONDOMS, Trait.LIKES_BIG_TITS, Trait.LIKES_CUTE };
        public bool allowAdditionalTraits { get; set; } = true;
        public ObservableCollection<Trait> blockedTraits { get; set; } = new ObservableCollection<Trait>() { Trait.NASTY_SPERM, Trait.TASTY_SPERM };
        public IEnumerable<Trait> traitValues
        {
            get { return Enum.GetValues(typeof(Trait)).Cast<Trait>(); }
        }
        public HashSet<String> races { get; set; } = new HashSet<string>() { "black", "white", "east asian", "south asian", "middle-eastern" };

        public string Error { get { return this["eyeColour"] + this["hairColour"] + this["skinColour"]; } }  // This is the only object level validation I care about
        public string this[string columnName]
        {
            get { return IsValid(columnName); }
        }

        private string IsValid(string propertyName)
        {

            switch (propertyName)
            {
                case "eyeColour":
                case "hairColour":
                case "skinColour":
                    Object value = this.GetType().GetProperty(propertyName).GetValue(this);
                    Debug.WriteLine(propertyName+ ": " + (value == null));
                    if (races.Contains(race))
                    {
                        return null;
                    }
                    else if (!String.IsNullOrWhiteSpace(value.ToString()))
                    {
                        return null;
                    }
                    else
                    {
                        string errorString = ti.ToTitleCase(propertyName);
                        errorString += " must be set if race is not one of ";
                        errorString += String.Join(",", races);
                        errorString += ".\n\n";
                        return errorString;
                    }
                default:
                    return null;  // Don't care about this validation
            }
        }

        public bool IsValid()
        {
            return string.IsNullOrEmpty(this.Error);
        }

        public override string ToString()
        {
            return name;
        }

        public string ToYML()
        {
            String toString = "---\n";
            toString += "type: " + type + "\n";
            toString += "enabled: " + enabled.ToString().ToUpper() + "\n";
            toString += "priority: " + priority + "\n";
            toString += "name: " + name + "\n";
            toString += "age: " + age + "\n";
            toString += "race: " + race + "\n";
            toString += "eye colour: " + eyeColour.ToLower() + "\n";
            toString += "hair colour: " + hairColour.ToLower() + "\n";
            toString += "skin colour: " + skinColour.ToLower() + "\n";
            toString += "figure: " + figure + "\n";
            toString += "personality: " + personality + "\n";
            toString += "traits:\n";
            foreach (Trait trait in traits)
            {
                toString += " - " + trait + "\n";
            }
            toString += "allow additional traits: " + allowAdditionalTraits.ToString().ToUpper() + "\n";
            if (allowAdditionalTraits)
            {
                toString += "blocked traits:\n";
                foreach (Trait trait in blockedTraits)
                {
                    toString += " - " + trait + "\n";
                }
            }
            return toString;
        }

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    enum Type
    {
        MALE
    }

    enum Age
    {
        EARLY_TWENTIES, TWENTIES, THIRTIES, FORTIES, FIFTIES, OLD
    }

    enum Figure
    {
        AVERAGE, SKINNY, TONED, MUSCULAR, THICKSET, PAUNCHY, FAT
    }

    enum Personality
    {
        JERK, SELFISH, AVERAGE, ROMANTIC, CARING
    }

    enum Trait
    {
        BAD_DANCER, BIG_BALLS, BIG_COCK_HEAD, BOASTFUL, CHARMING, COLD_HEARTED,
        CONSCIENTOUS, CRUDE, DOESNT_WANT_KIDS, DULL, FASHIONABLE, GOOD_DANCER,
        HANDSOME, HATES_CONDOMS, IMPREGNATOR, INTERESTING, LIKES_BIG_TITS,
        LIKES_CASUAL, LIKES_CUTE, LIKES_ELEGANT, LIKES_MED_TITS, LIKES_ORAL,
        LIKES_SEXY, LIKES_SMALL_TITS, LOWLIFE, MAGIC_FINGERS, MISANTHROPE,
        NASTY_SPERM, NO_BEFRIEND, PREFERS_SEX, REPAIRMAN, SLEAZY, TACITURN,
        TASTY_SPERM, THICK_COCK, UGLY, VIGOROUS_LOVER, WANTS_KIDS
    }
}
